/*
 * $Id: Sttp.h,v 1.4 2006-02-22 08:00:02 bacon Exp $
 */

#ifndef _XPP_NET_STTP_CLASS_
#define _XPP_NET_STTP_CLASS_

#include <xpp/net/SttpBase.h>
#include <xpp/net/SttpCmd.h>
#include <xpp/bas/HashTable.h>
#include <xpp/bas/RC4.h>

namespace xpp
{
	namespace net
	{

		class Sttp: public SttpBase 
		{
		public:
			Sttp (Transmittable* s = XP_NULL, Address* a = XP_NULL);
			virtual ~Sttp ();
		
			void reset ();

			xp_size_t maxRawCmdLen () const
			{
				return max_raw_cmd_len;
			}
			void setMaxRawCmdLen (xp_size_t v) 
			{
				max_raw_cmd_len = v;
			}
		
			xp_size_t maxArgCount () const 
			{
				return max_arg_count;
			}
			void setMaxArgCount (xp_size_t v) 
			{
				max_arg_count = v;
			}
			
			bool optEncAlways () const
			{
				return opt_enc_always;
			}

			void setOptEncAlways (bool opt)
			{
				opt_enc_always = opt;
			}

			bool optEncSend () const
			{
				return opt_enc_send;
			}
			void setOptEncSend (bool opt) 
			{
				opt_enc_send = opt;
			}

			bool optEncReceive () const
			{
				return opt_enc_receive;
				// however, there's no setOptEncRecv
			}
		
			bool optSendNewline () const
			{
				return opt_send_newline;
			}	
			void setOptSendNewline (bool opt) 
			{
				opt_send_newline = opt;
			}

			//void getReceivePasswd (xp_byte_t** pwd, xp_size_t* psz) 
			//{
			//	rc4_receive.getPasswd (pwd, psz);
			//}
			void setReceivePasswd (const xp_byte_t* pwd, xp_size_t psz) 
			{
				rc4_receive.setPasswd (pwd, psz);
			}
			//void getSendPasswd (xp_byte_t** pwd, xp_size_t* psz) 
			//{
			//	rc4_send.getPasswd (pwd, psz);
			//}
			void setSendPasswd (const xp_byte_t* pwd, xp_size_t psz) 
			{
				rc4_send.setPasswd (pwd, psz);
			}
		
			typedef int (Sttp::*CmdProc) (const SttpCmd& cmd);
			int  addCmd        (const xp_char_t* name, CmdProc proc);
			int  removeCmd     (const xp_char_t* name);
			void removeAllCmds ();
		
			int receiveCmd  (SttpCmd* cmd);
			int processCmd  (const SttpCmd& cmd);

			int sendCmd  (const SttpCmd& cmd);
			int sendCmd  (const xp_char_t* name, xp_size_t nargs, ...);
			int sendCmdL (const xp_char_t* name, xp_size_t nargs, ...);
			int sendCmdL (const xp_char_t* name, xp_size_t nmlen, xp_size_t nargs, ...);
		
			//
			// additional error codes 
			//
			enum 
			{
				ERR_CMDNAME = SttpBase::__NERRCODES__, // cmd name expected
				ERR_CMDPROC,      // user cmd proc returned -1
				ERR_UNKNOWNCMD,   // unknown command received
				ERR_TOOLONGCMD,
				ERR_SEMICOLON,
				ERR_TOOMANYARGS,
				ERR_WRONGARG,
				ERR_WRONGCHAR,
				__NERRCODES__
			};
		
			const xp_char_t* errorStr () const;
		
		protected:
			enum 
			{
				MAX_RAW_CMD_LEN  = 1024 * 1000,
				MAX_ARG_COUNT    = 20
			};
		
			xp_size_t max_raw_cmd_len;
			xp_size_t max_arg_count;
			xp_size_t raw_cmd_len;
		
			bool opt_enc_always;
			bool opt_enc_send;
			bool opt_enc_receive;
			bool opt_send_newline;

			xpp::bas::RC4 rc4_send;
			xpp::bas::RC4 rc4_receive;
		
			typedef xpp::bas::HashTable<xpp::bas::String,CmdProc> CmdDict;
			CmdDict cmd_dict;
		
			enum TokType 
			{
				T_STRING      = 1,
				T_IDENT       = 2,
				T_SEMICOLON   = 3,
				T_COMMA       = 4,
				T_ENC         = 5
			};

			TokType          token_type;
			xpp::bas::String token_value;
			
			int     get_char      (xp_cint_t* c = XP_NULL);
			int     get_token     (bool first = false);
			int     get_ident     ();
			int     get_string    ();
			xp_cint_t translate_escaped_char (xp_cint_t c);
			bool    is_ident_char (xp_cint_t c);
			int     put_char      (xp_cint_t c);

			virtual int preprocess_cmd (const SttpCmd& cmd);
			virtual int postprocess_cmd (const SttpCmd& cmd);
		};
		
	}
}
#endif
		
